#include <XnCppWrapper.h>
#include <vector>
#include "ChordCircle.h"
#include "utils.h"


ChordCircle::ChordCircle()
{
	mColor.push_back(0.);
	mColor.push_back(1.);
	mColor.push_back(0.);
	minRadius = 50;
	maxRadius = 100;
	mKey = C;
	curCol = mKey;
	UpdateColor(curCol);
}

ChordCircle::~ChordCircle()
{
	cInner.clear();
	cOuter.clear();
	mColor.clear();
}

/*void ChordCircle::DrawCircle(MidiPlayer::Chords key)
{
	DrawRays();
}*/

/*
Draw everything, with emphasis on the current key
*/
void ChordCircle::Draw(Chords key, bool all)
{
	//First, draw the circles
	mKey = key;
	glColor3d(mColor[0], mColor[1], mColor[2]);
	float cenX = (float)maxX/2.f;
	float cenY = (float)maxY/2.f;
	DrawCircle(cenX, cenY, (float)minRadius, 12, true);
	DrawCircle(cenX, cenY, (float)maxRadius, 12, false);

	//Second, draw the current key in the middle
	char* keyName = getKeyName(mKey);
	UpdateColor(key);
	glColor3d(mColor[0], mColor[1], mColor[2]);
	printw(cenX, cenY, 0.f, "%s", keyName);
	
	//Third, draw the letters around the circle
	curCol = C;
	UpdateColor(curCol);
	glColor3d(mColor[0], mColor[1], mColor[2]);
	DrawLetters(cenX, cenY, (float)(maxRadius*2 + minRadius)/3);

	//Fourth, draw the rays to separate the areas
	curCol = C;
	UpdateColor(curCol);
	glColor3d(mColor[0], mColor[1], mColor[2]);
	DrawRays();
	cInner.clear();//Clear when done
	cOuter.clear();

	glColor3d(0., 0., 0.);
	DrawInstruments();
}

void ChordCircle::DrawLetters(float cx, float cy, float r)
{
	//Draws the chord names around the circle
	float theta = 2 * (float)3.1415926 / 12.f; 
	float c = cosf(theta);//precalculate the sine and cosine
	float s = sinf(theta);
	float t;

	/*float x = r;//we start at angle = 0 
	float y = 0; */
	float start = -1.57079633f;//degrees
	float x = cosf(start) * r;// + cx;
	float y = sinf(start) * r;// + cy;

	for(int ii = 0; ii < 12.f; ii++) 
	{ 
		//glVertex3f(x + cx, y + cy, 0.f);//output vertex 
		printw(x + (cx - 20.f), y + (cy + 20.f), 0.f, getKeyName(curCol));
        
		//apply the rotation matrix
		t = x;
		x = c * x - s * y;
		y = s * t + c * y;

		//Update color
		int newColKey = ((int)curCol + 1) % 12;
		curCol = static_cast<Chords>(newColKey);
		UpdateColor(curCol);
		glColor3d(mColor[0], mColor[1], mColor[2]);
	}  
}

void ChordCircle::DrawCircle(float cx, float cy, float r, int num_segments, bool min) 
{ 
	float theta = 2 * (float)3.1415926 / float(num_segments); 
	float c = cosf(theta);//precalculate the sine and cosine
	float s = sinf(theta);
	float t;

	/*float x = r;//we start at angle = 0 
	float y = 0; */
	float start = -1.83259571f;//radians
	float x = cosf(start) * r;// + cx;
	float y = sinf(start) * r;// + cy;

	glBegin(GL_LINE_LOOP); 
	for(int ii = 0; ii < num_segments; ii++) 
	{ 
		glVertex3f(x + cx, y + cy, 0.f);//output vertex 
		if (min)
		{
			//Add points to inner circle point vectors
			std::vector<float> pts;
			pts.push_back(x + cx);
			pts.push_back(y + cy);
			cInner.push_back(pts);
		}
		else
		{
			//Add to outer
			std::vector<float> pts;
			pts.push_back(x + cx);
			pts.push_back(y + cy);
			cOuter.push_back(pts);
		}
        
		//apply the rotation matrix
		t = x;
		x = c * x - s * y;
		y = s * t + c * y;

		//Update color
		int newColKey = ((int)curCol + 1) % 12;
		curCol = static_cast<Chords>(newColKey);
		UpdateColor(curCol);
		glColor3d(mColor[0], mColor[1], mColor[2]);
	} 
	glEnd(); 
}


void ChordCircle::DrawRays()
{
	//Draws the chord names around the circle
	

	for(int i = 0; i < (int)cInner.size(); i++) 
	{ 
		//glVertex3f(x + cx, y + cy, 0.f);//output vertex 
		//printw(x + (cx - 20.f), y + (cy + 20.f), 0.f, getKeyName(curCol));
		glBegin(GL_LINES);
		glVertex3f(cInner[i][0], cInner[i][1], 0.f);
		glVertex3f(cOuter[i][0], cOuter[i][1], 0.f);
		glEnd();
        
		//apply the rotation matrix
		//Update color
		int newColKey = ((int)curCol + 1) % 12;
		curCol = static_cast<Chords>(newColKey);
		UpdateColor(curCol);
		glColor3d(mColor[0], mColor[1], mColor[2]);
	}  
}

void ChordCircle::UpdateColor(Chords k)
{
	switch(k)
	{
		case C: //Red
			mColor[0] = 1.;
			mColor[1] = 0.;
			mColor[2] = 0.;
			break;
		case G: //Pink
			mColor[0] = 1.;
			mColor[1] = 20./255.;
			mColor[2] = 147./255.;
			break;
		case D: //Magenta
			mColor[0] = 199./255.;
			mColor[1] = 21./255.;
			mColor[2] = 133./255.;
			break;
		case A: //Violet
			mColor[0] = 138./255.;
			mColor[1] = 43./255.;
			mColor[2] = 226./255.;
			break;
		case E: //Blue	205 (or 255 for brighter blue)
			mColor[0] = 0;
			mColor[1] = 0;
			mColor[2] = 205./255.;
			break;
		case B: //Dodgerblue
			mColor[0] = 30./255.;
			mColor[1] = 144./255.;
			mColor[2] = 1.;
			break;
		case Gb: //Cyan
			mColor[0] = 0;
			mColor[1] = 1.;
			mColor[2] = 1.;
			break;
		case Db: //Spring
			mColor[0] = 0;
			mColor[1] = 1.;
			mColor[2] = 127./255.;
			break;
		case Ab: //Green/lime
			mColor[0] = 50./255.;
			mColor[1] = 205./255.;
			mColor[2] = 50./255.;
			break;
		case Eb: //"Lawn" green
			mColor[0] = 124./255.;
			mColor[1] = 252./255.;
			mColor[2] = 0;   
			break;
		case Bb: //Yellow
			mColor[0] = 1.;
			mColor[1] = 1.;
			mColor[2] = 0;
			break;
		case F: //Orange
			mColor[0] = 1.;
			mColor[1] = 165./255.;
			mColor[2] = 0;
			break;
		default: {
			//anything?
			break; }
	}
}


void ChordCircle::DrawInstruments()
{
	//Draw Instruments
	float xOff = 30.f;
	float width = (float)GetDif((double)rc.left, (double)rc.right);
	float height = (float)GetDif((double)rc.top, (double)rc.bottom);

	//Piano
	printw(rc.left + xOff, height/4.f, 0.f, "Piano");

	//Organ
	printw(rc.left + xOff, height/2.f, 0.f, "Organ");

	//Strings
	printw(rc.left + xOff, 3.f*height/4.f, 0.f, "Strings");


	//Trumpet
	printw(rc.right - xOff*4, height/4.f, 0.f, "Trumpet ");

	//Alto Sax
	printw(rc.right - xOff*4, height/2.f, 0.f, "Alto Sax");

	//Ocarina
	printw(rc.right - xOff*4, 3.f*height/4.f, 0.f, "Ocarina ");
}